1. Field of the Invention
This invention relates generally to concurrent access to shared objects, and more particularly, to a system and method for implementing multiple, alternative techniques for concurrent access to shared objects.
2. Description of the Related Art
In concurrent software designs and implementations, it is often important to ensure that one thread does not observe partial results of an operation that is concurrently being executed by another thread. Such assurances are important for practical and productive software development because, without them, it can be extremely difficult to reason about the interactions of concurrent threads.
Such assurances have often been provided by using locks to prevent other threads from accessing the data affected by an ongoing operation. Unfortunately, the use of locks may give rise to a number of problems, both in terms of software engineering and in terms of performance. First, the right “balance” of locking must be achieved, so that correctness can be maintained, without preventing access to an unnecessary amount of unrelated data (thereby possibly causing other threads to wait when they do not have to). Furthermore, if not used carefully, locks can result in deadlock, causing software to freeze up. Moreover, it is frequently the case that whenever a thread is delayed (e.g. preempted) while holding a lock, other threads must wait before being able to acquire that lock.
Transactional memory is a paradigm that allows the programmer to design code as if multiple locations can be accessed and/or modified in a single atomic step. As typically defined, a transactional memory interface allows a programmer to designate certain sequences of operations as “transactions”, which are guaranteed by the transactional memory implementation to either take effect atomically and in their entirety (in which case we say that they succeed), or have no externally visible effect (in which case we say that they fail). Thus, in many cases, it is possible to complete multiple operations with no possibility of another thread observing partial results, even without holding any locks. The transactional paradigm can significantly simplify the design of concurrent programs.
Transactional memory is widely recognized as a promising paradigm for allowing a programmer to make updates to multiple locations in a manner that is apparently atomic, while addressing many of the problems associated with the use of locks. In general, transactional memory can be implemented in hardware, with the hardware directly ensuring that a transaction is atomic, or in software that provides the “illusion” that the transaction is atomic, even though in fact it is executed in smaller atomic steps by the underlying hardware.
Most designs implement or support only a single type of transactional memory implementation. Moreover, a programmer generally must know about, and write code to support, the particular interfaces for implementing transactional memory. Furthermore, even if a system supports a particular transactional memory implementation that implementation may not be guaranteed for all transactions. For example, a system may support a “best-effort” transaction memory implementation, but since the implementation is “best-effort” not all transactions may be guaranteed to be supported. Thus, a programmer may wish to include functionality to fall back to more flexible, if slower, transactional memory implementation that may guarantee support for all transactions. In order to do so, the programmer may have to specifically write code to support both the faster “best-effort” implementation and the slower fallback implementation at every location in the application for which the programmer wishes to execute instructions atomically.